import {
    Cesium3DTileset,
    Transforms,
    Cartesian3,
    Model as CesiumModel,
    HeadingPitchRange,
    Color as CesiumColor,
    ScreenSpaceEventHandler,
    defined as CesiumDefined,
    ScreenSpaceEventType,
    CallbackProperty,
    Matrix4,
    Ellipsoid,
    Math as CesiumMath,
    LabelStyle,
    PolygonHierarchy,
    Cartesian2,
    VerticalOrigin,
    Cartographic,
    HeadingPitchRoll,
    PolylineArrowMaterialProperty,
} from 'cesium'

/**
 * 方式1：关于模型的平移，xy轴 分别考虑沿着纬线方向和经线方向移动，z轴的考虑根据屏幕坐标判断向下还是向下，然后自己模拟速度来进行
 * 方式2：xyz 的移动都根据屏幕坐标来计算方向，然后模拟速度来进行
 */
class LoadLayers {
    axisCenter: any;
    selectedEntity: any;
    mouseClickPointCar3: any;
    modelCenter: any;
    moveType: string;
    moveDistance: number;
    baseCenterTransform: any;
    defaultConfig: any;
    verticalMoveParams: any;

    constructor() {
        this.axisCenter = undefined;//xyz 坐标轴的中心点,实际就是模型的中心点
        this.selectedEntity = undefined;//当前选中的entity
        this.baseCenterTransform = undefined;//基于中心点的变化矩阵

        this.mouseClickPointCar3 = undefined;// 鼠标按下xyz轴的时候记录下按下的笛卡尔3坐标

        this.modelCenter = undefined;//模型的中心点

        this.moveType = "";//平移类型E-东,N-北,U-向上

        this.moveDistance = 0;//平移的距离

        this.defaultConfig = {
            "X_Axis": CesiumColor.RED,
            "Y_Axis": CesiumColor.GREEN,
            "Z_Axis": CesiumColor.BLUE
        }
        //垂直于地球表面移动参数定义
        this.verticalMoveParams = {
            lastPosition: undefined,
            currentPosition: undefined
        }
    }

    /**
     *加载3dtiles的数据
     * @param viewer
     */
    load3dtiles = async (viewer: any, option: { "url": string, maximumScreenSpaceError: number, position: { x: number, y: number, z: number } }) => {
        let {url, maximumScreenSpaceError, position} = option;
        let _this = this;
        const Cesium3DTilesetOptions = {
            maximumScreenSpaceError: maximumScreenSpaceError,
            maximumNumberOfLoadedTiles: 1024,
            foveatedTimeDelay: 2,
            progressiveResolutionHeightFraction: 0.3,// 数值偏于0能够让初始加载变得模糊
            skipLevelOfDetail: true,
            maximumMemoryUsage: 1024,
            cullRequestsWhileMovingMultiplier: 10,// 值越小能够更快的剔除
            cullRequestsWhileMoving: true,   //优化选项。不要请求可能因为相机的移动而返回时未使用的磁贴
            cullWithChildrenBounds: true,  //优化选项。是否使用其子对象边界体积的联合来剔除瓷砖
            loadSiblings: true, // 如果为 true 则不会在已加载完模型后，自动从中心开始超清化模型
            immediatelyLoadDesiredLevelOfDetail: false,
            preloadWhenHidden: true,
            preferLeaves: true,
            dynamicScreenSpaceErrorDensity: 0.5, // 数值加大，能让周边加载变快
            dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没，反正放着吧先
            dynamicScreenSpaceError: true, // 根据测试，有了这个后，会在真正的全屏加载完之后才清晰化房屋
        }
        const tileset = await Cesium3DTileset.fromUrl(url, Cesium3DTilesetOptions)
        viewer.scene.primitives.add(tileset)
        const originalSphere = tileset.boundingSphere
        const radius = originalSphere.radius
        viewer.zoomTo(tileset, new HeadingPitchRange(0.5, -0.5, radius * 3))
        //显示包围盒
        // tileset.debugShowBoundingVolume=true;
        //显示内容包围盒
        // tileset.debugShowContentBoundingVolume=true;

        // this.loadXYZ(viewer, originalSphere.center, tileset);
        this.loadXYZ(viewer, tileset, originalSphere.center, radius)
    }

    /**
     * 加载glb或者gltf  ./model/CesiumDrone.glb
     * @param viewer
     * @param option
     */
    loadGlbOrGltf = async (viewer: any, option: { "url": string, position: { x: number, y: number, z: number } }) => {
        let {url, position} = option;
        const origin = Cartesian3.fromDegrees(position['x'], position['y'], position['z']);
        const modelMatrix = Transforms.eastNorthUpToFixedFrame(origin);
        const model = await CesiumModel.fromGltfAsync({
            // url: './model/CesiumDrone.glb',
            url: url,
            show: true,
            modelMatrix: modelMatrix,
            scale: 50.0,
            minimumPixelSize: 128,
            maximumScale: 50,
            allowPicking: false,
            debugShowBoundingVolume: false,
            debugWireframe: false,
            id: "mdzz_drone"
        })
        viewer.scene.primitives.add(model);
        viewer.camera.flyTo({
            destination: Cartesian3.fromDegrees(position['x'], position['y'], position['z'] + 1000),
            orientation: {
                heading: CesiumMath.toRadians(175.0),
                pitch: CesiumMath.toRadians(-35.0),
                roll: 0.0
            }
        })
    }

    /**
     * 加载对应的xyz轴
     * @param viewer
     * @param tileset
     * @param center 中心笛卡尔3坐标
     * @param radius 半径
     */
    loadXYZ(viewer: any, tileset: any, center: any, radius: number) {
        let that = this;
        that.modelCenter = center.clone();
        //添加x轴的entity
        let xEntity = viewer.entities.add({
            name: 'X_Axis',
            polyline: {
                positions: new CallbackProperty(() => {
                    let endPoint = that.enuToWorld(that.modelCenter, 'E', radius);
                    return [
                        that.modelCenter,
                        endPoint
                    ]
                }, false),
                width: 50,
                //箭头线材质
                material: new PolylineArrowMaterialProperty(
                    CesiumColor.RED
                ),
            }
        });
        //添加Y轴的entity
        let yEntity = viewer.entities.add({
            name: 'Y_Axis',
            polyline: {
                positions: new CallbackProperty(() => {
                    let endPoint = that.enuToWorld(that.modelCenter, 'N', radius);
                    return [
                        that.modelCenter,
                        endPoint
                    ]
                }, false),
                width: 50,
                material: new PolylineArrowMaterialProperty(
                    CesiumColor.GREEN
                ),
            }
        });
        //添加z轴的entity
        let zEntity = viewer.entities.add({
            name: 'Z_Axis',
            polyline: {
                positions: new CallbackProperty(() => {
                    let endPoint = that.enuToWorld(that.modelCenter, 'U', radius);
                    return [
                        that.modelCenter,
                        endPoint
                    ]
                }, false),
                width: 50,
                material: new PolylineArrowMaterialProperty(
                    CesiumColor.BLUE
                ),
            }
        });
        let handler = new ScreenSpaceEventHandler(viewer.canvas);
        handler.setInputAction((movement: any) => {
            let pickedObject = viewer.scene.pick(movement.position);
            if (CesiumDefined(pickedObject)) {
                let selectEntity: any = undefined;
                let name = "";
                if (pickedObject.id?.name === 'X_Axis') {
                    selectEntity = xEntity;
                    name = 'X_Axis';
                    that.moveType = 'E';
                } else if (pickedObject.id?.name === 'Y_Axis') {
                    selectEntity = yEntity;
                    name = 'Y_Axis';
                    that.moveType = 'N';
                } else if (pickedObject.id?.name === 'Z_Axis') {
                    selectEntity = zEntity;
                    name = 'Z_Axis';
                    that.moveType = 'U';
                }
                //修改选中的entity的颜色
                if (selectEntity) {
                    that.verticalMoveParams.lastPosition = movement.position.clone();
                    let cartesian = that.getMouseCar3(viewer, movement.position)
                    that.mouseClickPointCar3 = cartesian;
                    that.selectedEntity = selectEntity;
                    //修改选中的entity的颜色
                    that.selectedEntity.polyline.material = new PolylineArrowMaterialProperty(
                        CesiumColor.YELLOW
                    );
                    //禁用拖拽地图
                    viewer.scene.screenSpaceCameraController.enableRotate = false;
                }
                viewer.scene.requestRender();
            }
        }, ScreenSpaceEventType.LEFT_DOWN);
        handler.setInputAction((movement: any) => {
            if (!CesiumDefined(that.selectedEntity)) {
                return;
            }
            let cartesian = that.getMouseCar3(viewer, movement.endPosition);
            if (CesiumDefined(cartesian)) {
                that.verticalMoveParams.currentPosition = movement.endPosition.clone();
                that.modelCenter = that.moveChangeCenterWay1(viewer, cartesian);
                // 计算变换矩阵-改变模型的根位置
                let transformModel = Transforms.eastNorthUpToFixedFrame(that.modelCenter.clone());
                tileset._root.transform = transformModel;
                viewer.scene.requestRender();
            }
        }, ScreenSpaceEventType.MOUSE_MOVE);

        handler.setInputAction(() => {
            if (that.selectedEntity) {
                let name=that.selectedEntity.name;
                //还原之前选中的
                that.selectedEntity.polyline.material = new PolylineArrowMaterialProperty(
                    that.defaultConfig[name]
                );
                that.selectedEntity=undefined;
            }
            that.moveType = '';
            viewer.scene.screenSpaceCameraController.enableRotate = true;
            viewer.scene.requestRender();
        }, ScreenSpaceEventType.LEFT_UP);


    }

    /**
     * 将enu转换为世界坐标
     * @param center
     * @param type
     * @param radius
     */
    enuToWorld(center: any, type: string, radius: number) {
        // 创建 ENU 坐标系的到世界坐标系的变换矩阵
        const enuTransform = Transforms.eastNorthUpToFixedFrame(center);
        if (type === 'E') {
            // 创建ENU坐标系的方向向量
            const eastVector = new Cartesian3(radius, 0, 0);
            // 将ENU坐标系的方向向量转换到世界坐标系中
            const eastInWorld = Matrix4.multiplyByPoint(enuTransform, eastVector, new Cartesian3());
            return eastInWorld;
        } else if (type === 'N') {
            const northVector = new Cartesian3(0, radius, 0);
            const northInWorld = Matrix4.multiplyByPoint(enuTransform, northVector, new Cartesian3());
            return northInWorld;
        } else if (type === 'U') {
            const upVector = new Cartesian3(0, 0, radius);
            const upInWorld = Matrix4.multiplyByPoint(enuTransform, upVector, new Cartesian3());
            return upInWorld;
        }
    }

    /**
     * 方式1：主要计算鼠标的实时的位置，来移动，移动过程中不同点之间差值不一样
     * 鼠标移动过程中的中心点的变化
     * @param currentMouseCar3
     */
    moveChangeCenterWay1(viewer: any, currentMouseCar3: any) {
        let runStart = this.car3Tojwd(viewer, this.mouseClickPointCar3.clone());
        let runEnd = this.car3Tojwd(viewer, currentMouseCar3.clone());
        let jdAdd: number = 0;
        let wdAdd: number = 0;
        let heightAdd: number = 0;
        if (this.moveType === 'E') { //向东运动,纬度、高度不变，经度变化
            jdAdd = runEnd.x - runStart.x;
        } else if (this.moveType === 'N') { //向北运动，经度、高度不变，纬度变化
            wdAdd = runEnd.y - runStart.y;
        } else if (this.moveType === 'U') {
            if (this.verticalMoveParams.lastPosition && this.verticalMoveParams.currentPosition) {
                //根据屏幕坐标 即像素判断鼠标是往上移动还是往下移动
                let flag = 0;
                //笛卡尔，y方向移动的差值
                let car2Ycz=this.verticalMoveParams.lastPosition.y-this.verticalMoveParams.currentPosition.y;
                if (car2Ycz>0) {
                    flag = 1; //向上移动
                } else {
                    flag = -1; //向下移动
                }
                console.log("当前垂直移动的距离",Math.abs(car2Ycz))
                heightAdd = 1 * (Math.abs(car2Ycz)/5) * flag;
                this.verticalMoveParams.lastPosition = this.verticalMoveParams.currentPosition.clone();
            }
        }
        this.mouseClickPointCar3 = Cartesian3.fromDegrees(runStart.x + jdAdd, runStart.y + wdAdd, runStart.z + heightAdd);
        let currentCenterJwd = this.car3Tojwd(viewer, this.modelCenter.clone());
        return Cartesian3.fromDegrees(currentCenterJwd.x + jdAdd, currentCenterJwd.y + wdAdd, currentCenterJwd.z + heightAdd);
    }

    /**
     * 获取鼠标的当前位置的笛卡尔3坐标
     * @param viewer
     * @param position 鼠标事件的position
     */
    getMouseCar3(viewer: any, position: any) {
        let cartesian: any = null;
        let pick = viewer.scene.pick(position);
        if (viewer.scene.globe.depthTestAgainstTerrain) {
            if (CesiumDefined(pick)) {
                //获取到了pick，获取倾斜摄影和模型表面的坐标，只有在开启地形且不使用默认地形准确
                cartesian = viewer.scene.pickPosition(position);
            } else {
                //获取加载地形后的坐标
                let ray = viewer.camera.getPickRay(position);//获取一条射线
                cartesian = viewer.scene.globe.pick(ray, viewer.scene);
            }
        } else {
            cartesian = viewer.scene.camera.pickEllipsoid(position, viewer.scene.globe.ellipsoid);
        }
        return cartesian;
    }

    /**
     * 笛卡尔3转经纬度
     * @param viewer
     * @param cartesianPosition
     */
    car3Tojwd(viewer: any, cartesianPosition: any) {
        const ellipsoid = viewer.scene.globe.ellipsoid;
        const cartographicPosition = ellipsoid.cartesianToCartographic(cartesianPosition);
        let x = CesiumMath.toDegrees(cartographicPosition.longitude);
        let y = CesiumMath.toDegrees(cartographicPosition.latitude);
        let z = cartographicPosition.height;
        return {x, y, z}
    }


}

export default new LoadLayers()




